package com.own.core.operation;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FlushModeType;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.Metamodel;

import com.own.app.OwnApp;
import com.own.core.object.Dao;
import com.own.core.object.User;
import com.own.core.object.admin.Group;
 
import com.own.core.object.admin.Role;
import com.own.core.object.admin.Setting;
import com.own.core.object.admin.pages.Page;
import com.own.core.object.lookup.Gender;
import com.own.core.object.lookup.Lookup;
import com.own.core.object.lookup.address.City;
import com.own.core.object.lookup.address.Country;




public class DbOperation/* implements InitializingBean */{

	private EntityManager entityManager;
	private static DbOperation ME = null;

	public static DbOperation getME() {
		if (ME == null) {
			ME = new DbOperation();
		}

		return ME;
	}

	private DbOperation() {
		entityManager = OwnApp.entityManager;
		testData();
	}

	public Object load(Class cls, Object id) {
		return entityManager.find(cls, id);
	}

	public boolean saveOrUpdate(Dao dao) {
		entityManager.setFlushMode(FlushModeType.COMMIT);
		entityManager.persist(dao);
		entityManager.flush();

		return true;

	}

	public boolean refresh(Dao dao) {

		entityManager.refresh(dao);

		return true;

	}

	public boolean merge(Dao dao) {
		// entityManager.flush();
		// entityManager.merge(dao) ;
		// entityManager.flush();
		return true;

	}

	public boolean delete(Dao dao) {

		// dao.setDelete(true);
		// saveOrUpdate(dao);
		//
		dao.delete();
		entityManager.setFlushMode(FlushModeType.AUTO);
		entityManager.remove(dao);
		return true;
	}

	public boolean undo(Dao dao) {

		dao.setDelete(false);
		saveOrUpdate(dao);

		// dao.delete();
		// entityManager.setFlushMode(FlushModeType.AUTO);
		// entityManager.remove(dao);
		return true;
	}

	// private
	public List<Object> listAll(Class cls) {
		CriteriaBuilder cBuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery cQuery = cBuilder.createQuery(cls);
		cQuery.from(cls);
		Query q = entityManager.createQuery(cQuery);
		return q.getResultList();

	}

	public List<Object> listSortedAll(Class cls, Map filter, String sortfield,
			boolean asc, int first, int count) {

		CriteriaBuilder cBuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery cQuery = cBuilder.createQuery(cls);

		Root<Dao> root = cQuery.from(cls);
		cQuery.select(root);

		if (!filter.isEmpty()) {
			Set keys = filter.keySet();
			for (Object obj : keys) {
				Field key = (Field) obj;
				Path fieldPath = root.get(key.getName());

				cQuery.where(cBuilder.like(fieldPath, filter.get(key)
						.toString()));

			}// end for

		}// end if

		cQuery.orderBy(asc ? cBuilder.asc(root.get(sortfield)) : cBuilder
				.desc(root.get(sortfield)));

		Query q = entityManager.createQuery(cQuery);
		q.setFirstResult(first);
		q.setMaxResults(count);
		return q.getResultList();

	}
	public List<Object> listSortedAllByJPQL(Class cls, Map filter, String sortfield,
			boolean asc, int first, int count) {
//		EntityManagerFactory emf = Persistence
//				.createEntityManagerFactory("DbOperation");
//		entityManager = emf.createEntityManager();
//		entityManager.getTransaction().begin();
		String sql="from "+cls.getSimpleName();
		
		
		Query q = entityManager.createQuery(sql);
		q.setFirstResult(first);
		q.setMaxResults(count);
		return q.getResultList();

	}

	public List<Object> list(Class cls, Map param) {

		CriteriaBuilder cBuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery cQuery = cBuilder.createQuery(cls);
		Root root = cQuery.from(cls);
		for (Object objKey : param.keySet()) {

			Path att = root.get(objKey.toString());
			cQuery.where(cBuilder.equal(att, param.get(objKey)));
		}

		TypedQuery q = entityManager.createQuery(cQuery);

		return q.getResultList();
	}

	public List<Object> listByJPQL(Class cls, Map param) {

		String jpaQl = "select x from " + cls.getName() + " x ";
		if (param.size() > 0) {
			jpaQl += " where ";
		}
		for (Object objKey : param.keySet()) {
			jpaQl += " x." + objKey.toString() + "=";

			if (param.get(objKey).getClass().getName().indexOf("String") > -1) {

				jpaQl += "'" + param.get(objKey) + "'";
			} else {
				jpaQl += param.get(objKey);
			}

		}
		return entityManager.createQuery(jpaQl).getResultList();
	}

	public long countAll(Class cls) {
		CriteriaBuilder qb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Long> cq = qb.createQuery(Long.class);
		cq.select(qb.count(cq.from(cls)));
		return entityManager.createQuery(cq).getSingleResult();

	}

	public void executeQuery(String sql) {
		entityManager.createNativeQuery(sql).executeUpdate();

	}

	public List executeNamedQuery(String NamedQuery, Map param) {
		Query query = entityManager.createNamedQuery(NamedQuery);
		if (param != null) {
			for (Object objKey : param.keySet()) {

				Object objValue = param.get(objKey);
				if (objValue instanceof Number) {
					query.setParameter(objKey.toString(), (Number) objValue);
				} else {

					query.setParameter(objKey.toString(), objValue);
				}

			}// end for
		}// end if
		return query.getResultList();

	}

	public List executeNamedQuery(String NamedQuery) {

		return executeNamedQuery(NamedQuery, null);

	}

	public void afterPropertiesSet() throws Exception {
	}

	protected EntityManager getEntityManager() {

		return entityManager;
	}

	private void testData() {
		if (true)
			return;
//		Gender male = new Gender();
//		male.setName("Male");
//
//		Gender female = new Gender();
//		female.setName("Female");
//		saveOrUpdate(male);
//		saveOrUpdate(female);
		// if(true)return;
		Country c = new Country("egypt");
		City city = new City("cairo", c);
		City city1 = new City("alex", c);
		City city2 = new City("tanta", c);
		City city3 = new City("aswan", c);
		City city4 = new City("banha", c);
		City city5 = new City("6 octobar", c);
		saveOrUpdate(c);
		saveOrUpdate(city);
		saveOrUpdate(city1);
		saveOrUpdate(city2);
		saveOrUpdate(city3);
		saveOrUpdate(city4);
		saveOrUpdate(city5);

		Country ac = new Country("KSA");
		City acity = new City("riyadh", ac);
		City acity1 = new City("makka", ac);
		City acity2 = new City("damam", ac);
		City acity3 = new City("madina", ac);
		City acity4 = new City("khobar", ac);
		City acity5 = new City("tahef", ac);
		saveOrUpdate(ac);
		saveOrUpdate(acity);
		saveOrUpdate(acity1);
		saveOrUpdate(acity2);
		saveOrUpdate(acity3);
		saveOrUpdate(acity4);
		saveOrUpdate(acity5);

//		ActionObject action1 = new ActionObject("Create");
//		ActionObject action2 = new ActionObject("Update");
//		ActionObject action3 = new ActionObject("Delete");
//		ActionObject action4 = new ActionObject("List");
//		ActionObject action5 = new ActionObject("Copy");
//		ActionObject action6 = new ActionObject("Approve");
//		ActionObject action7 = new ActionObject("Disapprove");

//		saveOrUpdate(action1);
//		saveOrUpdate(action2);
//		saveOrUpdate(action3);
//		saveOrUpdate(action4);
//		saveOrUpdate(action5);
//		saveOrUpdate(action6);
//		saveOrUpdate(action7);

		Page  homeMenu= new Page("Home");
		Page adminMenu = new Page("Admin");
		saveOrUpdate(homeMenu);
		saveOrUpdate(adminMenu);

		
		Page userMenu = new Page("User",User.class.getName(),homeMenu);
		Page GroupMenu = new Page("Group",Group.class.getName(),homeMenu);
		Page RoleMenu = new Page("Role",Role.class.getName(),homeMenu);
		Page settingMenu = new Page("Setting",Setting.class.getName(),adminMenu);
		Page countryMenu = new Page("Country",Country.class.getName(),adminMenu);
		Page cityMenu = new Page("City",City.class.getName(),adminMenu);
//		Page genderMenu = new Page("Gender",Gender.class.getName(),adminMenu);
//		Page actionMenu = new Page("Action",Action.class.getName(),adminMenu);
		Page menuMenu = new Page("Page",Page.class.getName(),adminMenu);
		
		
		
		
		saveOrUpdate(userMenu);
		saveOrUpdate(GroupMenu);
		saveOrUpdate(RoleMenu);
		saveOrUpdate(settingMenu );
		saveOrUpdate(countryMenu );
		saveOrUpdate(cityMenu );
//		saveOrUpdate(genderMenu );
//		saveOrUpdate(actionMenu );
		/*
		ObjectRole  userRole=new ObjectRole ("User",User.class.getName(),userMenu);
		saveOrUpdate(userRole);
		
		ObjectRole  roleRole=new ObjectRole ("Role",Role.class.getName(),RoleMenu);
		saveOrUpdate(roleRole);
		
		ObjectRole  groupRole=new ObjectRole ("Group",Group.class.getName(),RoleMenu);
		saveOrUpdate(groupRole);
		
		ObjectRole  settingRole=new ObjectRole ("Setting",Setting.class.getName(),settingMenu);
		saveOrUpdate(settingRole);
		
		ObjectRole  counrtyRole=new ObjectRole ("Country",Country.class.getName(),countryMenu);
		saveOrUpdate(counrtyRole);
		
		ObjectRole  cityRole=new ObjectRole ("City",City.class.getName(),cityMenu);
		saveOrUpdate(cityRole);
		ObjectRole  genderRole=new ObjectRole ("Gender",Gender.class.getName(),genderMenu);
		saveOrUpdate(genderRole);
		ObjectRole  actionRole=new ObjectRole ("Action",ActionObject.class.getName(),actionMenu);
		saveOrUpdate(actionRole);
		ObjectRole  menuRole=new ObjectRole ("Menu",Menu.class.getName(),menuMenu);
		saveOrUpdate(menuRole);
		
		*/
		User user=new User("Admin","hggi");
		saveOrUpdate(user);
		
		
		
		Group group=new Group("Admin");
		saveOrUpdate(group);
		
		
		
		
		
		

	}

}
